<template>
  <div>
    <h1>计算属性和监听</h1>
    名字：<input type="text" v-model="user.firstName"><br>
    姓氏：<input type="text" v-model="user.lastName"><br>
    <!-- 深度监听姓：<input type="text" v-model="user.child.lastName"><br> -->
    姓名计算简写get：<input type="text" v-model="fullNameCmpj"><br>
    姓名计算全写：<input type="text" v-model="fullNameCmpq"><br>
    姓名监视：<input type="text" v-model="fullNameWatch"><br>
    watchEffect姓名：<input type="text" v-model="fullNameWatchEf">
  </div>
</template>

<script lang="ts">
//defineComponent 是一个函数，作用就是定义一个组件，在内部传入对象，配置对象
import { defineComponent, ref, reactive, computed, watch, watchEffect } from 'vue';


export default defineComponent({
  name: 'App',
  setup() {
    //vue3当中计算属性的用法
    const user = reactive({
      firstName: '爱国',
      lastName: '蒋',
      child: {
        firstName: '爱家',
        lastName: '小蒋'
      }
    })

    //需求：根据 firstName 和 lastName 得到全名
    //使用计算属性  记得引入

    //一、计算属性

    //1、computed简写  只有 get
    const fullNameCmpj = computed(() => {
      return user.firstName + user.lastName
    })
    console.log(fullNameCmpj) // computedRef对象
    //2、computed的标准   有 get 和 set
    //注意：单写get函数不行，会报错，写全了则不会报错
    const fullNameCmpq = computed({
      get() {
        return user.firstName + '-' + user.lastName
      },
      set(value: string) {//如果不规定value的数据类型，ts会进行类型推断，默认为unknown数据类型
        // // console.log(value)
        // if (value.indexOf('-') < 0) {
        //     user.firstName = value
        // } else {
        //   let arr = value.split('-');
        //   if (arr[0].length < 1) {
        //     user.firstName = '';
        //   } else if (arr[1].length < 1) {
        //     user.lastName = ''
        //   } else {
        //     user.firstName = arr[0];
        //     user.lastName = arr[1];
        //   }
        // }
        let arr = value.split('-');
        user.firstName = arr[0];
        user.lastName = arr[1];
      }
    })

    //二、watch 监视
    //    监视可以 一个watch监视一个数据，也可以一个watch监视多个数据，推荐使用一个watch监视一个数据，思路清晰

    //watch  使用时记得引入

    //造一个 监视的数据 fullNameWatch
    const fullNameWatch = ref('')//初始值为空串
    //1、监听一个数据写法：
    //watch(第一个参数：监视的对象/数据，第二个参数是回调函数)
    // watch(user,()=>{
    //   //虽然watch没有开启深度监视，但是对象user的第二层child，也是能监听的到的。
    //   // fullNameWatch.value = user.firstName+'-'+user.child.lastName
    //   fullNameWatch.value = user.firstName+'-'+user.lastName
    // },{
    //   deep:true,//开启深度监视
    //   immediate:true//立即触发  即页面加载完成后都立即触发watch
    // })
    // //为了实现双向变化，这里要加一个反向监视
    // //(2)通过反向监视，实现了数据的双向变化
    // watch(fullNameWatch,(newValue)=>{ //两个参数：newValue、oldValue
    //   //原理：拿到新值，进行处理。
    //   let arr = newValue.split('-')
    //   user.firstName = arr[0]
    //   user.lastName = arr[1]
    // })

    //watchEffect   vue3新增的，就相当于 watch加了一个 immediate。
    //使用时，记得先引入
    const fullNameWatchEf = ref("");
    //watchEffect  只有一个参数，回调函数
    watchEffect(() => {
      fullNameWatchEf.value = user.firstName + '-' + user.lastName
    })
    //watchEffect 的反向监视
    watchEffect(() => {
      let arr = fullNameWatchEf.value.split('-')
      user.firstName = arr[0]
      user.lastName = arr[1]
    })

    //2、一个watch同时监听，多个数据
    //当watch监听多个数据时，无论哪一个发生变化，都会触发回调函数
    //第一个参数：数组；将要监听的多个数据，都放到数组中
    //第二个参数：回调函数； 监听数据发生改变时会触发
    //参数数组：对于基本数据类型来说，直接写就好--fullNameWatch；
    //         对于引用数据类型来说，写成函数形式
    watch([fullNameWatch, () => user.firstName, () => user.lastName], (values, oldValues) => {// values 是数组，发生改变时的新值;oldValues 是旧值
      console.log(values)// values 是数组，发生改变时的新值
      console.log(oldValues)//oldValues 是旧值
      //分情况而定写多种逻辑    谁变化，执行谁对应的逻辑
      //分两种情况：1、当 user.firstName 或 user.lastName 发生变化时，获取新的 fullNameWatch   
      //           2、当fullNameWatch 发生变化时，获取新的user.firstName 与 user.lastName 
      if (values[1] != oldValues[1] || values[2] != oldValues[2]) {
        fullNameWatch.value = values[1] + '-' + values[2]
      } else if (values[0] != oldValues[0]) {
        let arr = values[0].split('-')
        user.firstName = arr[0]
        user.lastName = arr[1]
      }
    }, {
      deep: true,
      immediate:true
    })


    return {
      //只有返回出来的值，才能在template模板中访问的到
      user,
      fullNameCmpj,
      fullNameCmpq,
      fullNameWatch,
      fullNameWatchEf
    }
  },



});
</script>

<style>

</style>
